package excel

import (
	"fmt"
	"mime/multipart"
	"strings"

	"github.com/pkg/errors"

	"github.com/xuri/excelize/v2"
)

const (
	File             = "file"
	DefaultFileIndex = 0
)

func AnalyzeExcel(importFile *multipart.FileHeader, sheetName string) ([][]string, error) {
	// 如果sheetName为空，则默认为Sheet1
	if sheetName == "" {
		sheetName = "Sheet1"
	}
	f, _ := importFile.Open()
	defer f.Close()
	file, err := excelize.OpenReader(f)
	if err != nil {
		fmt.Println(fmt.Sprintf("打开文件流失败，err:%v", err))
		return nil, errors.New("上传文件有损坏，请重新上传！")
	}
	defer func() {
		// 关闭工作簿
		if err := file.Close(); err != nil {
			fmt.Println(fmt.Sprintf("关闭工作簿失败，err:%v", err))
		}
	}()
	// 获取sheetName上所有单元格
	rows, err := file.GetRows(sheetName)
	return rows, err
}

func GetHeaderMap(excelContent [][]string, headerIndex int) (headerMap map[int]string, err error) {
	headerMap = make(map[int]string)
	if excelContent == nil || len(excelContent) == 0 {
		return nil, errors.New("excel内容为空")
	}

	if headerIndex >= len(excelContent) {
		return nil, errors.New("headerIndex超出范围")
	}

	header := excelContent[headerIndex]
	for i, h := range header {
		headerMap[i] = strings.TrimSpace(h)
	}
	return
}

func GetDataMap(excelContent [][]string, beginIndex int) (dataMap []map[int]string, err error) {
	dataMap = make([]map[int]string, 0)
	if excelContent == nil || len(excelContent) == 0 {
		return nil, errors.New("excel内容为空")
	}

	if beginIndex >= len(excelContent) {
		return nil, errors.New("beginIndex超出范围")
	}

	excelContent = excelContent[beginIndex:]
	for i, row := range excelContent {
		if len(row) == 0 {
			continue
		}
		dataMap = append(dataMap, make(map[int]string))
		for j, cell := range row {
			dataMap[i][j] = strings.TrimSpace(cell)
		}
	}
	return
}

func AnalyzeHeaderExcelToData(multipartForm *multipart.Form, sheetName string, indexExcel, indexRaw int) (dataMap []map[int]string, err error) {
	fileHeader := multipartForm.File["file"][indexExcel]
	excelContent, err := AnalyzeExcel(fileHeader, sheetName)
	if err != nil {
		return nil, err
	}

	dataMap, err = GetDataMap(excelContent, indexRaw)
	if err != nil {
		return nil, err
	}

	if len(dataMap) == 0 {
		return nil, errors.New("excel数据为空")
	}

	return dataMap, nil
}

var BlankValue = "/"

type ExcelDataConfig struct {
	Index        int
	Name         string
	Desc         string
	Value        string
	ValueMap     map[string]string
	DefaultValue string
	Nullable     bool
}

func GetExcelDataConfigValue(dataMap map[int]string, config *ExcelDataConfig) (value string, err error) {
	if config == nil {
		return "", errors.New("excel数据配置为空")
	}

	value, _ = dataMap[config.Index]

	if config.Nullable && value == "" {
		return "", errors.New("数据未填写")
	}

	if value == "" && config.DefaultValue != "" {
		value = config.DefaultValue
	}

	if v, ok := config.ValueMap[value]; ok {
		value = v
	}
	return replaceValue(value), err
}

func replaceValue(value string) string {
	if value == BlankValue {
		value = ""
	}
	return value
}

func ParseExcelData(multipartForm *multipart.Form, sheetName string, dataBeginIndex int) (dataMap []map[int]string, err error) {
	var (
		excelContent [][]string
	)

	fileHeader := multipartForm.File[File][DefaultFileIndex]
	if excelContent, err = AnalyzeExcel(fileHeader, sheetName); err != nil {
		return nil, errors.WithMessage(err, "解析页签失败")
	}
	if dataMap, err = GetDataMap(excelContent, dataBeginIndex); err != nil {
		return nil, errors.WithMessage(err, "解析excel数据失败")
	}
	if len(dataMap) == 0 {
		return nil, errors.New("excel数据为空")
	}

	return
}

func SetMergeCellMap(mergeCellMap map[string]*MergeCellInfo, mergeCellKey string, cellIndex string) {
	if _, ok := mergeCellMap[mergeCellKey]; !ok {
		mergeCellMap[mergeCellKey] = &MergeCellInfo{
			MergeStartIndex: cellIndex,
			MergeEndIndex:   cellIndex,
		}
	} else {
		mergeCellMap[mergeCellKey].MergeEndIndex = cellIndex
	}
	return
}

type MergeCellInfo struct {
	MergeStartIndex string
	MergeEndIndex   string
}

func SetSheet(file *excelize.File, sheetData *SheetData) (err error) {
	var (
		streamWriter = &excelize.StreamWriter{}
	)

	file.NewSheet(sheetData.SheetName)
	if streamWriter, err = file.NewStreamWriter(sheetData.SheetName); err != nil {
		return errors.WithMessage(err, "创建流写入器失败")
	}

	defer func() {
		streamWriter.Flush()
	}()

	if sheetData.ColWidthInfo != nil {
		streamWriter.SetColWidth(sheetData.ColWidthInfo.Min, sheetData.ColWidthInfo.Max, sheetData.ColWidthInfo.Width)
	}

	for _, row := range sheetData.SheetHeaderInfos {
		if err = streamWriter.SetRow(row.Axis, row.Data); err != nil {
			return errors.WithMessage(err, "设置头信息失败")
		}
	}

	for _, row := range sheetData.RowDataList {
		if err = streamWriter.SetRow(row.Axis, row.Data); err != nil {
			return errors.WithMessage(err, "设置行信息失败")
		}
	}

	for _, mergeCellInfo := range sheetData.MergeCellInfos {
		if mergeCellInfo.MergeEndIndex == mergeCellInfo.MergeStartIndex {
			continue
		}
		streamWriter.MergeCell(mergeCellInfo.MergeStartIndex, mergeCellInfo.MergeEndIndex)
	}

	return
}

type SheetData struct {
	ColWidthInfo     *ColWidthInfo    //列宽信息
	RowDataList      []*RowData       //行数据
	SheetHeaderInfos []*RowData       //头信息
	SheetName        string           //页签
	MergeCellInfos   []*MergeCellInfo //合并信息
}

type RowData struct {
	Axis string        //开始坐标 例如 A1
	Data []interface{} //数据
}

type ColWidthInfo struct {
	Min   int     //开始列 例如 1  必须大于0
	Max   int     //结束列 例如 2	必须大于0
	Width float64 //列宽 默认 20  最大255   0或大于255 无效
}

func (r *RowData) GetDataIndexValue(index int) (value interface{}) {
	if index < 0 || index >= len(r.Data) {
		return
	}
	return r.Data[index]
}
